import geohash2
import s2sphere

def s2Encode(lat, lon, level):
    latlng = s2sphere.LatLng.from_degrees(lat, lon)
    cell = s2sphere.CellId.from_lat_lng(latlng).parent(level)
    return cell.to_token()

def s2Decode(s2):
    cellid=s2sphere.CellId.from_token(s2)
    latlng=cellid.to_lat_lng()
    latitude=latlng.lat().degrees
    longitude=latlng.lng().degrees
    return latitude, longitude
def geohashEncode(lat, lng, level):
    return geohash2.encode(lat, lng, precision=level)

def geohashDecode(geohash):
    return geohash2.decode(geohash)

BASESEQUENCE = '0123456789bcdefghjkmnpqrstuvwxyz'
def adjacent(geohash, direction):
  """Return the adjacent geohash for a given direction."""
  # Based on an MIT licensed implementation by Chris Veness from:
  #   http://www.movable-type.co.uk/scripts/geohash.html
  assert direction in 'nsew', "Invalid direction: %s"%direction
  assert geohash, "Invalid geohash: %s"%geohash
  neighbor = {
    'n': [ 'p0r21436x8zb9dcf5h7kjnmqesgutwvy', 'bc01fg45238967deuvhjyznpkmstqrwx' ],
    's': [ '14365h7k9dcfesgujnmqp0r2twvyx8zb', '238967debc01fg45kmstqrwxuvhjyznp' ],
    'e': [ 'bc01fg45238967deuvhjyznpkmstqrwx', 'p0r21436x8zb9dcf5h7kjnmqesgutwvy' ],
    'w': [ '238967debc01fg45kmstqrwxuvhjyznp', '14365h7k9dcfesgujnmqp0r2twvyx8zb' ]
  }
  border = {
    'n': [ 'prxz',     'bcfguvyz' ],
    's': [ '028b',     '0145hjnp' ],
    'e': [ 'bcfguvyz', 'prxz'     ],
    'w': [ '0145hjnp', '028b'     ]
  }
  last = geohash[-1]
  parent = geohash[0:-1]
  t = len(geohash) % 2
  # Check for edge cases
  if (last in border[direction][t]) and (parent):
    parent = adjacent(parent, direction)
  return parent + BASESEQUENCE[neighbor[direction][t].index(last)]

def geohashNeighbors(geohash):
  """Return all neighboring geohashes."""
  return {
    'n':  adjacent(geohash, 'n'),
    'ne': adjacent(adjacent(geohash, 'n'), 'e'),
    'e':  adjacent(geohash, 'e'),
    'se': adjacent(adjacent(geohash, 's'), 'e'),
    's':  adjacent(geohash, 's'),
    'sw': adjacent(adjacent(geohash, 's'), 'w'),
    'w':  adjacent(geohash, 'w'),
    'nw': adjacent(adjacent(geohash, 'n'), 'w'),
    'c':  geohash
  }

def geohashBoxCoords(geohash):
    lat, lon= geohash2.decode(geohash)
    precision=len(geohash)
    lat_size = 180.0 / (2 ** (5 * precision // 2))
    lon_size = 360.0 / (2 ** (5 * (precision // 2 + 1)))
    min_lat = float(lat) - lat_size / 2
    max_lat = float(lat) + lat_size / 2
    min_lon = float(lon) - lon_size / 2
    max_lon = float(lon) + lon_size / 2

    return min_lat, min_lon, max_lat, max_lon

if __name__ == '__main__':
    s2Grid=s2Encode(30.5, 114.5, 14)
    print(s2Grid)
    lat, lng = s2Decode(s2Grid)
    print(lat, lng)
    geoGrid=geohashEncode(30.5, 114.5, 6)
    print(geoGrid)
    print(geohashDecode(geoGrid))
    # {'n': 'wt3mt3', 'ne': 'wt3mt9', 'e': 'wt3mt8', 'se': 'wt3mmx', 's': 'wt3mmr', 'sw': 'wt3mmp', 'w': 'wt3mt0', 'nw': 'wt3mt1', 'c': 'wt3mt2'}
    print(geohashNeighbors(geoGrid))
    min_lat, min_lon, max_lat, max_lon=geohashBoxCoords(geoGrid)
    print(min_lat, min_lon, max_lat, max_lon)